package com.mathdroid.gui.main.buffs;

import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.HashMap;

import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;

import com.mathdroid.gui.ImageLoader;
import com.mathdroid.gui.main.DroidComboBoxModel;
import com.mathdroid.gui.main.EGlobalStrings;
import com.mathdroid.model.Model;
import com.mathdroid.model.buffs.BuffTemplate;
import com.mathdroid.model.buffs.BuffTemplates;
import com.mathdroid.model.buffs.GroupBuffDebuff;
import com.mathdroid.model.enums.EBuffType;
import com.mathdroid.persistence.Serializer;

/**
 * This panel gives the option to edit the used buffs, load and save templates.
 */
public class BuffsPanel extends JPanel {
	/**
	 * Default UID.
	 */
	private static final long serialVersionUID = 1L;
	
	/**
	 * The buff templates.
	 */
	private JComboBox templates = null;
	
	/**
	 * Button to save a template.
	 */
	private final JButton save = new JButton();
	
	/**
	 * Button to delete a template.
	 */
	private final JButton delete = new JButton();
	
	/**
	 * UI component constraints.
	 */
	private final GridBagConstraints c = new GridBagConstraints();
	
	/**
	 * The width of the grid.
	 */
	private static final int GRID_WIDTH = 3;
	
	/**
	 * The spacing between components.
	 */
	private static final int SPACING = 10;
	
	/**
	 * The weight of "heavy" components.
	 */
	private static final int HEAVY_WEIGHT = 100;
	
	/**
	 * The scroll pane for the buff groups.
	 */
	private final JScrollPane sp = new JScrollPane();
	
	/**
	 * The edge length of the save/delete buttons.
	 */
	private static final int BUTTON_EDGE = 25;
	
	/**
	 * The serializer.
	 */
	private Serializer s = new Serializer();
	
	/**
	 * The image loader.
	 */
	private final ImageLoader il = new ImageLoader();
	
	/**
	 * This is a panel inside this panel. It is necessary to have this because
	 * of the use of BorderLayout. The content should be in the NORTH, not in
	 * the center.
	 */
	private final JPanel content = new JPanel();
	
	/**
	 * Standard constructor to create the buffs panel.
	 */
	public BuffsPanel() {
		super();
		
		this.setLayout(new GridBagLayout());
		this.content.setLayout(new GridBagLayout());
		
		this.buildComboBox();
		this.buildSaveButton();
		this.buildDeleteButton();
		this.addBuffs();
		this.buildScrollPane();
		
		this.templates.configureEditor(
				templates.getEditor(), 
				Model.getProfile().getBuffTemplate().toString());
		
		this.setPreferredSize(new Dimension(0, 0));
	}

	/**
	 * Build the scroll pane and viewport.
	 */
	private void buildScrollPane() {
		this.c.fill = GridBagConstraints.BOTH;
		this.c.gridx = 0;
		this.c.gridy = 1;
		this.c.weightx = HEAVY_WEIGHT;
		this.c.weighty = HEAVY_WEIGHT;
		this.c.gridwidth = GRID_WIDTH;
		this.c.insets = new Insets(0, 0, 0, 0);
		this.add(this.sp, this.c);
		this.sp.setViewportView(this.content);
	}

	/**
	 * Add the buff groups to the content panel.
	 */
	private void addBuffs() {
		int gridy = 1;
		final HashMap<EBuffType, BuffGroup> groups = 
			new HashMap<EBuffType, BuffGroup>();
		
		for (EBuffType type : EBuffType.getAllTypes()) {
			groups.put(type, new BuffGroup(
					type.toString(), gridy, SPACING, GRID_WIDTH, type));
			gridy++;
		}
		
		for (GroupBuffDebuff gb : Model.getProfile().getBuffTemplate()) {
			groups.get(gb.getType()).addBuff(gb);
		}
		
		for (EBuffType type : EBuffType.getAllTypes()) {
			if (groups.get(type).getGroupSize() > 0) {
				this.content.add(
						groups.get(type), groups.get(type).getConstraints());
			}
		}
	}

	/**
	 * Build the button to delete templates.
	 */
	private void buildDeleteButton() {
		this.delete.setToolTipText(EGlobalStrings.DELETE_TEMPLATE.toString());
		this.delete.setPreferredSize(
				new Dimension(BUTTON_EDGE, BUTTON_EDGE));
		this.delete.setIcon(this.il.getImage("delete"));
		
		this.c.fill = GridBagConstraints.NONE;
		this.c.gridx = 2;
		this.c.gridy = 0;
		this.c.weightx = 1;
		this.c.weighty = 1;
		this.c.gridwidth = 1;
		this.c.insets = new Insets(SPACING, 0, SPACING, SPACING);
		
		this.add(this.delete, this.c);	
		this.delete.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(final ActionEvent e) {
				Object o = templates.getSelectedItem();
				if (o instanceof BuffTemplate) {
					BuffTemplates t = s.getBuffTemplates();
					t.remove(((BuffTemplate) o).toString());
					s.serialize(t);
					templates.removeItem(o);
					templates.configureEditor(templates.getEditor(), null);
				}
			}
		});
	}

	/**
	 * Build the button to save a template.
	 */
	private void buildSaveButton() {
		this.save.setToolTipText(EGlobalStrings.SAVE_TEMPLATE.toString());
		this.save.setPreferredSize(
				new Dimension(BUTTON_EDGE, BUTTON_EDGE));
		this.save.setIcon(this.il.getImage("add"));
		
		this.c.fill = GridBagConstraints.NONE;
		this.c.gridx = 1;
		this.c.gridy = 0;
		this.c.weightx = 1;
		this.c.weighty = 1;
		this.c.gridwidth = 1;
		this.c.insets = new Insets(SPACING, 0, SPACING, SPACING);
		
		this.add(this.save, this.c);	
		this.save.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(final ActionEvent e) {
				saveTemplate();
				refreshTemplates();
			}
		});
	}

	/**
	 * Build the templates combo box.
	 */
	private void buildComboBox() {
		this.templates = new JComboBox(new DroidComboBoxModel());
		BuffTemplates b = this.s.getBuffTemplates();
		
		for (BuffTemplate i : b.values()) {
			this.templates.addItem(i);
		}
		
		this.templates.setEditable(true);
		
		this.c.fill = GridBagConstraints.HORIZONTAL;
		this.c.gridx = 0;
		this.c.gridy = 0;
		this.c.weightx = HEAVY_WEIGHT;
		this.c.weighty = 1;
		this.c.gridwidth = 1;
		this.c.insets = new Insets(SPACING, SPACING, SPACING, SPACING);
		
		this.add(this.templates, this.c);
		this.templates.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(final ActionEvent e) {
				Object o = templates.getSelectedItem();
				if (o instanceof BuffTemplate) {
					delete.setEnabled(true);
					Model.setBuffs((BuffTemplate) o);
				}
				
			}
		});
		
		this.templates.getEditor().getEditorComponent()
				.addKeyListener(new KeyListener() {
			@Override
			public void keyPressed(final KeyEvent e) { 
				
				if (e.getKeyCode() == KeyEvent.VK_ENTER) {
					saveTemplate();
					refreshTemplates();
				} else {
					delete.setEnabled(false);
				}
			}
			@Override
			public void keyReleased(final KeyEvent arg0) { }
			@Override
			public void keyTyped(final KeyEvent arg0) { }
		});
	}

	/**
	 * Save the template to the persistence.
	 */
	private void saveTemplate() {
		Object o = templates.getEditor().getItem();
		BuffTemplates t = s.getBuffTemplates();
		BuffTemplate buffs = Model.getProfile().getBuffTemplate();
		String name = buffs.toString();
		boolean valid = true;
		
		if (o instanceof String) {
			name = (String) o;
			if (name.equals("")) {
				valid = false;
			}
		}
		
		if (valid) {
			buffs.setName(name);
			
			/* Put the template into the persistence. */
			t.put(buffs.toString(), buffs);
			s.serialize(t);
			
			this.delete.setEnabled(true);
			
			try {
				JOptionPane.showMessageDialog(Model.getDroidFrame(),
						"Saved buff template \"" + name + "\".\n"
							+ "Buff templates are shared between all profiles.",
						"Template saved", 
						JOptionPane.INFORMATION_MESSAGE);
				
				SwingUtilities.invokeLater(new Runnable() {
					public void run() {
						templates.configureEditor(
							templates.getEditor(), 
							Model.getProfile().getBuffTemplate().toString());
					}
				});
			} catch (Exception ex) {
				ex.printStackTrace();
			}
		}
	}

	/**
	 * Refresh the combo box model.
	 */
	private void refreshTemplates() {
		BuffTemplates t;
		templates.removeAllItems();
		t = s.getBuffTemplates();
		for (BuffTemplate temp : t.values()) {
			templates.addItem(temp);
		}
	}

}
